package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Panel;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import test.vo.CodeConfig;
import test.vo.Columns;
import test.vo.DbTable;
import test.vo.DbTableColumns;

/**
 * 
 * @author xuejianxin
 *
 */
public class CodeGeneratorMain {

	private JFrame frmxuejianxin;
	private final CodeGeneratorService service = new CodeGeneratorService();
	private JComboBox<String> selectDb;// 数据库下拉框
	private JComboBox<String> selectConfig;// 模板下拉框
	private Panel pnCheckboxes;// 模板选择
	private JTable jtTableList;// 数据库表列表
	private JTable jtColumnList;// 列
	private JLabel lbSelectTable;// 当前选中的第一个表
	private List<JCheckBox> cks;// 模板选择checkbox
	private CodeConfig codeConfig;
	private JTextField jtMod;// 所属模块
	private JTabbedPane tabs;// 页签
	private JTextArea jtSql;// sql 文本
	private JTextField jtTableNameSql;// sql 生成代码的类名称
	private JTextField jtTableNameQuery;// 查询表名
	// private boolean checkAll=true;
	private JCheckBox checkBoxAll;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					CodeGeneratorMain window = new CodeGeneratorMain();
					window.frmxuejianxin.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public CodeGeneratorMain() {
		initialize();
		init();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmxuejianxin = new JFrame();

		frmxuejianxin.setResizable(false);
		frmxuejianxin.setTitle("代码生成器支持多种数据库【xuejianxin@2018】");
		frmxuejianxin.setSize(1000, 600);
		frmxuejianxin.setLocationRelativeTo(null);
		frmxuejianxin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmxuejianxin.setIconImage(new ImageIcon(this.getClass().getResource("/test/code.jpg")).getImage());
		frmxuejianxin.getContentPane().setLayout(null);

		JLabel lbDb = new JLabel("数据库：");
		lbDb.setBounds(34, 10, 54, 15);
		frmxuejianxin.getContentPane().add(lbDb);

		selectDb = new JComboBox<String>();
		selectDb.addActionListener(onDbSelectChange);
		selectDb.setBounds(91, 7, 509, 21);
		frmxuejianxin.getContentPane().add(selectDb);

		JLabel lbConfig = new JLabel("代码模板：");
		lbConfig.setBounds(22, 38, 66, 15);
		frmxuejianxin.getContentPane().add(lbConfig);

		pnCheckboxes = new Panel();// checkbox
		FlowLayout flowLayout = (FlowLayout) pnCheckboxes.getLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);
		pnCheckboxes.setBounds(10, 90, 966, 57);
		frmxuejianxin.getContentPane().add(pnCheckboxes);

		selectConfig = new JComboBox<String>();
		selectConfig.addActionListener(onSelectConfigChange);
		selectConfig.setBounds(91, 35, 509, 21);
		frmxuejianxin.getContentPane().add(selectConfig);

		JButton btCode = new JButton("生成代码");
		btCode.setFont(new Font("宋体", Font.PLAIN, 21));
		btCode.addActionListener(onBtCodeClick);
		btCode.setBounds(730, 10, 246, 74);
		frmxuejianxin.getContentPane().add(btCode);

		JLabel lbMod = new JLabel("所属模块：");
		lbMod.setBounds(22, 63, 66, 15);
		frmxuejianxin.getContentPane().add(lbMod);

		jtMod = new JTextField();
		jtMod.setBounds(91, 63, 509, 21);
		frmxuejianxin.getContentPane().add(jtMod);

		// ----------------------页签1
		JPanel pnTab1 = new JPanel();
		pnTab1.setLayout(new BorderLayout());
		JPanel pnTable1 = new JPanel();
		FlowLayout pnTable1Layout = new FlowLayout();
		pnTable1Layout.setAlignment(FlowLayout.LEFT);
		pnTable1.setLayout(pnTable1Layout);

		JLabel lbTableNameQuery = new JLabel("表名[按回车模糊查询]：");
		lbTableNameQuery.setBounds(10, 9, 58, 15);
		jtTableNameQuery = new JTextField();
		jtTableNameQuery.addKeyListener(onJtTableNameQuery);
		jtTableNameQuery.setColumns(31);
//		jtTableNameQuery.setSize(300, 15);

		lbSelectTable = new JLabel();// "当前选中:"
		lbSelectTable.setSize(300, 15);
		lbSelectTable.setForeground(Color.RED);

		pnTable1.add(lbTableNameQuery);
		pnTable1.add(jtTableNameQuery);
		pnTable1.add(lbSelectTable);
		pnTab1.add(pnTable1, BorderLayout.NORTH);

		// table列表和列信息
		FlowLayout pnTableAndColumnLayout = new FlowLayout();
		pnTableAndColumnLayout.setAlignment(FlowLayout.LEFT);
		JPanel pnTableAndColumn = new JPanel();
		pnTableAndColumn.setLayout(pnTableAndColumnLayout);

		jtTableList = new JTable(new DbTable());
		jtColumnList = new JTable(new DbTableColumns());

		JScrollPane pnTableList = new JScrollPane(jtTableList) {
			private static final long serialVersionUID = 1L;

			public Dimension getPreferredSize() {
				return new Dimension(450, 330);
			}
		};

		JScrollPane pnColumnList = new JScrollPane(jtColumnList) {
			private static final long serialVersionUID = 1L;

			public Dimension getPreferredSize() {
				return new Dimension(500, 330);
			}
		};

		pnTableAndColumn.add(pnTableList);
		pnTableAndColumn.add(pnColumnList);

		pnTab1.add(pnTableAndColumn, BorderLayout.CENTER);
		// jTable 为你要监听的表
		jtTableList.addMouseListener(onJtDbClick);

		// ----------------------页签2
		JPanel pnTab2 = new JPanel();
		pnTab2.setLayout(new BorderLayout());
		JPanel pnSql1 = new JPanel();
		FlowLayout pnSql1Layout = new FlowLayout();
		pnSql1Layout.setAlignment(FlowLayout.LEFT);
		pnSql1.setLayout(pnSql1Layout);
		JLabel lbTableNameSql = new JLabel("虚拟表名：");
		lbTableNameSql.setForeground(Color.RED);
		lbTableNameSql.setBounds(10, 9, 58, 15);
		jtTableNameSql = new JTextField();
		jtTableNameSql.setText("MY_DEMO");
		jtTableNameSql.setColumns(50);
		pnSql1.add(lbTableNameSql);
		pnSql1.add(jtTableNameSql);
		pnTab2.add(pnSql1, BorderLayout.NORTH);
		jtSql = new JTextArea();
		jtSql.setFont(new Font("Monospaced", Font.PLAIN, 14));
		jtSql.setText("select 'id1' as id, sysdate create_date, 1.0 num from dual");
		jtSql.setToolTipText("请输入SQL");
		JScrollPane pnSql2 = new JScrollPane(jtSql);
		pnTab2.add(pnSql2, BorderLayout.CENTER);

		tabs = new JTabbedPane(JTabbedPane.TOP);
		tabs.setBounds(10, 153, 966, 400);
		tabs.add("从表生成代码[按shift键可多选]", pnTab1);
		tabs.add("从SQL生成代码", pnTab2);
		frmxuejianxin.getContentPane().add(tabs);
		// ----------------------页签

	}

	/**
	 * 初始化
	 */
	private void init() {
		List<File> fs = service.getConfigDb();
		for (File f : fs) {
			selectDb.addItem(f.getName());
		}
		fs = service.getConfigTemplates();
		for (File f : fs) {
			selectConfig.addItem(f.getName());
		}

	}

	/**
	 * 从表信息生成代码
	 * 
	 * @return
	 * @throws Exception
	 */
	private boolean toCodeFromTable() throws Exception {
		int[] rows = jtTableList.getSelectedRows();
		if (null == rows || rows.length == 0) {
			alert("请选择至少一条数据");
			return false;
		}

		String[][] selectTables = new String[rows.length][3];
		for (int i = 0; i < rows.length; i++) {
			selectTables[i][0] = (String) jtTableList.getModel().getValueAt(rows[i], 1);// 数据库
			selectTables[i][1] = (String) jtTableList.getModel().getValueAt(rows[i], 2);// 表名
			selectTables[i][2] = (String) jtTableList.getModel().getValueAt(rows[i], 3);// 表中文备注
			Map<String, Object> options = new HashMap<>();
			if (!"".equals(jtMod.getText().trim())) {// 判断是否填写模块
				options.put("mod", jtMod.getText().trim());
			}
			for (JCheckBox cb : cks) {
				if (cb.isSelected()) {
					options.put(cb.getName(), true);
				}
			}
			List<Columns> cs = service.getTableInfo((String) selectDb.getSelectedItem(), selectTables[i][0],
					selectTables[i][1]);
			CodeGenerate.setConfig(codeConfig);
			options.put(CodeGenerate.TABLE_NAME_ZN, selectTables[i][2]);
			CodeGenerate.toCode(selectTables[i][1], cs, options);
		}
		return true;
	}

	/**
	 * 从sql 生成代码
	 * 
	 * @return
	 * @throws Exception
	 */
	private boolean toCodeFromSql() throws Exception {
		String className = jtTableNameSql.getText();
		if (null == className || "".equals(className.trim())) {
			alert("请填写虚拟表名,用于生成类的名称");
			jtTableNameSql.requestFocus();
			return false;
		}

		String sql = jtSql.getText();
		if (null == sql || "".equals(sql.trim())) {
			alert("请输入sql");
			jtSql.requestFocus();
			return false;
		}
		Map<String, Object> options = new HashMap<>();
		if (!"".equals(jtMod.getText().trim())) {// 判断是否填写模块
			options.put("mod", jtMod.getText().trim());
		}
		for (JCheckBox cb : cks) {
			if (cb.isSelected()) {
				options.put(cb.getName(), true);
			}
		}
		List<Columns> cs = service.getSqlInfo((String) selectDb.getSelectedItem(), className, sql);
		CodeGenerate.setConfig(codeConfig);
		CodeGenerate.toCode(className, cs, options);

		return true;
	}

	private MouseListener onJtDbClick = new MouseAdapter() {
		public void mousePressed(MouseEvent e) {
			// if (e.getClickCount() == 2) { // 2表示双击
//				System.out.println("被双击了");
			refreshColumnList();
			// }
		}
	};

	/**
	 * 数据库select 事件
	 */
	private ActionListener onDbSelectChange = (ae) -> {
		refreshTableList(null);
		// 重置列信息
		jtColumnList.setModel(new DbTableColumns());
		lbSelectTable.setText("");
	};
	private ActionListener onCheckBoxClick = (ae) -> {
		JCheckBox cb = (JCheckBox) ae.getSource();
		if ("ck_all".equals(cb.getName())) {// 全选反选
			for (JCheckBox jcb : cks) {
				jcb.setSelected(cb.isSelected());
			}
		} else {
			boolean checkAll = true;
			for (JCheckBox jcb : cks) {
				checkAll = checkAll && jcb.isSelected();
			}
			checkBoxAll.setSelected(checkAll);
		}
	};
	/**
	 * 选择配置文件
	 */
	private ActionListener onSelectConfigChange = (ae) -> {
		String config = (String) selectConfig.getSelectedItem();
		try {
			codeConfig = service.readConfig(config);
		} catch (Exception ex) {
			alert("配置文件有错误,请检查文件" + config + ",错误信息:" + ex.getMessage());
			return;
		}
		pnCheckboxes.removeAll();
		cks = new ArrayList<JCheckBox>();
		pnCheckboxes.repaint();
		for (CodeConfig.Tempate t : codeConfig.getTemplates()) {
			JCheckBox cb = new JCheckBox(t.getName());
			cb.setSelected(false);
			cb.setName(t.getId());
			cb.addActionListener(onCheckBoxClick);
			pnCheckboxes.add(cb);
			cks.add(cb);
		}

		checkBoxAll = new JCheckBox(" 全   选   ");
		checkBoxAll.setSelected(false);
		checkBoxAll.setName("ck_all");
		checkBoxAll.addActionListener(onCheckBoxClick);
		checkBoxAll.setForeground(Color.RED);
		pnCheckboxes.add(checkBoxAll);

		pnCheckboxes.revalidate();
	};

	/**
	 * 代码生成按钮
	 */
	private ActionListener onBtCodeClick = (ae) -> {
		int tabId = tabs.getSelectedIndex();
		boolean success = false;

		try {
			if (0 == tabId) {
				success = toCodeFromTable();
			} else {
				success = toCodeFromSql();
			}
		} catch (Exception ex) {
			String msg = ex.getMessage();
			ex.printStackTrace();
			alert("代码生成失败,错误信息：" + msg.substring(0, Math.min(msg.length(), 100)));
			return;
		}
		if (success) {
			int r = JOptionPane.showConfirmDialog(frmxuejianxin, "代码生成成功,是否要打开代码生成目录?", "系统提示",
					JOptionPane.OK_CANCEL_OPTION);
			if (0 == r) {
				try {
					java.awt.Desktop.getDesktop().open(new File(codeConfig.getBaseDir()));
				} catch (Exception e) {

				}
			}
		}
	};

	/** 回车查询表 */
	private KeyAdapter onJtTableNameQuery = new KeyAdapter() {
		@Override
		public void keyPressed(KeyEvent ke) {
			if (ke.getKeyCode() == KeyEvent.VK_ENTER) // 判断按下的键是否是回车键
			{
				String tableName = jtTableNameQuery.getText();
				refreshTableList(tableName);
			}
		}
	};
	private volatile boolean isStartup = true;

	/**
	 * 刷新列信息
	 * 
	 * @param tableName
	 */
	private void refreshColumnList() {

		try {
			int[] rows = jtTableList.getSelectedRows();

			String[] selectTables = new String[3];
			// 只处理选中的第一个
			selectTables[0] = (String) jtTableList.getModel().getValueAt(rows[0], 1);// 数据库
			selectTables[1] = (String) jtTableList.getModel().getValueAt(rows[0], 2);// 表名
			selectTables[2] = (String) jtTableList.getModel().getValueAt(rows[0], 3);// 表中文备注
			lbSelectTable.setText("当前选中:" + selectTables[1]);
			List<Columns> cs = service.getTableInfo((String) selectDb.getSelectedItem(), selectTables[0],
					selectTables[1]);
			jtColumnList.setModel(new DbTableColumns(cs));

			for (int i = 0; i < DbTableColumns.colWidth.length; i++) {
				jtColumnList.getColumnModel().getColumn(i).setPreferredWidth(DbTableColumns.colWidth[i]);
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

	/**
	 * 刷新表格
	 * 
	 * @param tableName
	 */
	private void refreshTableList(String tableName) {
		boolean needAlert = true;
		if (isStartup) {
			needAlert = false;
			isStartup = false;
		}
		String config = (String) selectDb.getSelectedItem();
		try {
			if (null != tableName && !"".equals(tableName.trim())) {
				jtTableList.setModel(new DbTable(service.getTableList(config, tableName.trim())));
			} else {
				jtTableList.setModel(new DbTable(service.getTableList(config)));
			}
			for (int i = 0; i < DbTable.colWidth.length; i++) {
				jtTableList.getColumnModel().getColumn(i).setPreferredWidth(DbTable.colWidth[i]);
			}
			// jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			if (needAlert) {// 启动时连接不上数据库 不再弹出提示
				alert("config/db/" + config + "无法连接到数据库,请检查IP和用户名密码!");
			}
		}
	}

	private void alert(String msg) {
		JOptionPane.showMessageDialog(frmxuejianxin, msg);
	}
}
